package com.miplus.ccrm.report.service.cti;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.*;
import com.miplus.ccrm.report.config.redis.service.RedisService;
import com.miplus.ccrm.report.controller.dto.ivr.InGroupDetailDTO;
import com.miplus.ccrm.report.controller.vo.cti.CallReqVo;
import com.miplus.ccrm.report.controller.vo.cti.CallResVo;
import com.miplus.ccrm.report.controller.vo.cti.DialogueResVo;
import com.miplus.ccrm.report.controller.vo.ivr.*;
import com.miplus.ccrm.report.feign.FiImpAddVo;
import com.miplus.ccrm.report.feign.ICoreFeign;
import com.miplus.ccrm.report.mapper.CcSeaterMapper;
import com.miplus.ccrm.report.pojo.CcSeater;
import com.miplus.ccrm.report.pojo.TRecorder;
import com.miplus.ccrm.report.mapper.TRecorderMapper;
import com.miplus.ccrm.report.service.ExportService;
import com.miplus.ccrm.report.service.StatusConversionService;
import com.miplus.ccrm.report.utils.DateUtils;
import com.miplus.ccrm.report.utils.SpringContextUtil;
import com.miplus.ccrm.report.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
* @author pc
* @description 针对表【t_recorder】的数据库操作Service实现
* @createDate 2024-07-29 14:33:48
*/
@Slf4j
@Service
public class TRecorderServiceImpl extends MPJBaseServiceImpl<TRecorderMapper, TRecorder>
    implements TRecorderService{

    @Resource
    private ExportService exportService;
    @Resource
    private ICoreFeign iCoreFeign;
    @Resource
    private RedisService redisService;
    @Resource
    private CcSeaterMapper seaterMapper;
    @Resource
    private JDataService dataService;
    @Resource
    private StatusConversionService statusConversionService;

    //录音列表
//    @Override
//    public IPage<CallResvo> recordList(JSysUser user, CallReqVo paras) {
//        //xml-sql版
//        paras.setCurrentUsrid(user.getUsrid());
//        paras.setPhnStar(JUsrPerm.getPermission(user, JUsrPerm.DISSTAR_PHN));
//        return baseMapper.listCallRecords(
//                new Page<>(paras.getPageNum(), paras.getPageSize()),
//                paras
//        );
//    }
    @Override
    public IPage<CallResVo> recordList(JSysUser user, CallReqVo paras)
    {
        String $usrid = user.getUsrid();
        String phnstar = JUsrPerm.getPermission(user, JUsrPerm.DISSTAR_PHN);
        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                CallResVo.class,
                new MPJLambdaWrapper<TRecorder>()
                        .selectAs(TRecorder::getRecorderid, CallResVo::getUcallid)
                        .selectAs(TRecorder::getStarttime, CallResVo::getCrdt)
                        .selectAs(TRecorder::getAgentid, CallResVo::getUsrid)
                        .selectAs(TRecorder::getChanneldn, CallResVo::getDn)
                        .selectAs(TRecorder::getInfoid, CallResVo::getRecordurl)
                        .selectAs(TRecorder::getSpendtime, CallResVo::getActivespan)
                        .selectAs("(SELECT h2.waitspan FROM report_call_hist h2 WHERE h2.callmanagenumber = t.callid AND ROWNUM = 1)", CallResVo::getRingspan)
                        .selectAs(TRecorder::getInfodepart, CallResVo::getRecupload)
                        .selectAs("fun_getnames('CTI.CALLTYPE',t.calltype)", CallResVo::getCalltype)
                        //存在问题
                        //.selectAs("(SELECT fun_getnames('CTI.CALLRESULT',h2.callresult) FROM report_call_hist h2 WHERE h2.callmanagenumber = t.callid AND ROWNUM = 1)", CallResVo::getCallresult)
                        .selectAs(
                                "(SELECT fun_getnames('CTI.CALLRESULT', h2.callresult) " +
                                        "FROM report_call_hist h2 " +
                                        "WHERE h2.callmanagenumber = t.callid " +
                                        "AND h2.DEVTYPE = 'device' " +  // 优先查询device类型
                                        "AND ROWNUM = 1 " +
                                        "UNION ALL " +  // 如果没有device类型则执行原查询
                                        "SELECT fun_getnames('CTI.CALLRESULT', h3.callresult) " +
                                        "FROM report_call_hist h3 " +
                                        "WHERE h3.callmanagenumber = t.callid " +
                                        "AND NOT EXISTS ( " +  // 确保不存在device类型记录时才执行
                                        "SELECT 1 FROM report_call_hist h4 " +
                                        "WHERE h4.callmanagenumber = t.callid " +
                                        "AND h4.DEVTYPE = 'device' " +
                                        ") " +
                                        "AND ROWNUM = 1)",
                                CallResVo::getCallresult
                        )
                        .selectAs(String.format("fi_starSecu('%s','%s',t.telno,'%s')", $usrid, JUsrPerm.DISSTAR_PHN, phnstar), CallResVo::getAni)
                        .selectAs(String.format("fi_starSecu('%s','%s',t.teldnis,'%s')", $usrid, JUsrPerm.DISSTAR_PHN, phnstar), CallResVo::getDnis)
                        .selectAs("fun_getgrpname(t.agentid)", CallResVo::getGrpname)
                        .selectAs("fun_getusername(t.agentid)", CallResVo::getUsrname)
                        .select(TRecorder::getCallid, TRecorder::getTaskflag, TRecorder::getUpasrdt)
                        .exists("SELECT 1 FROM report_call_hist h WHERE h.callmanagenumber = t.callid "
                                + "AND ((h.devtype = 'device' AND t.channeldn != 'robotai') "
                                + "OR (h.devtype = 'vdn' AND t.channeldn = 'robotai')) "
                                + "AND h.talkspan > 0")
                        .notIn(TRecorder::getAgentid, "ivr", "qm")
                        .eq(JPubUtils.IsNotEmpty(paras.getUsrid()), TRecorder::getAgentid, paras.getUsrid())
                        .eq(JPubUtils.IsNotEmpty(paras.getCalltype()), TRecorder::getCalltype, paras.getCalltype())
                        .apply(JPubUtils.IsNotEmpty(paras.getCallresult()),
                                "(SELECT h2.callresult FROM report_call_hist h2 WHERE h2.callmanagenumber = t.callid AND ROWNUM = 1) = {0}",
                                paras.getCallresult())
                        .between(JPubUtils.IsNotEmpty(paras.getStartdt()),
                                TRecorder::getStarttime,
                                JPubUtils.StringToDate(paras.getStartdt()),
                                JPubUtils.StringToDate(paras.getEnddt()))
                        .ge(JPubUtils.IsNotEmpty(paras.getTalkspan1()), TRecorder::getSpendtime, paras.getTalkspan1())
                        .le(JPubUtils.IsNotEmpty(paras.getTalkspan2()), TRecorder::getSpendtime, paras.getTalkspan2())
                        .apply(JPubUtils.IsNotEmpty(paras.getPhone()), "(t.telno = {0} OR t.teldnis = {0})", paras.getPhone())
                        .apply(JPubUtils.IsNotEmpty(paras.getGrpid()), "fc_hasUsrInGroup(t.agentid, {0}) > 0", paras.getGrpid())
                        .orderByAsc(TRecorder::getStarttime)
        );
//        String $usrid=user.getUsrid();
//        String phnstar= JUsrPerm.getPermission(user, JUsrPerm.DISSTAR_PHN);
//        //2024-08 add Recupload
//        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
//                CallResvo.class,
//                new MPJLambdaWrapper<TRecorder>()
//                        .selectAs(TRecorder::getRecorderid,CallResvo::getUcallid)
//                        .selectAs(TRecorder::getStarttime,CallResvo::getCrdt)
//                        .selectAs(TRecorder::getAgentid,CallResvo::getUsrid)
//                        .selectAs(TRecorder::getChanneldn,CallResvo::getDn)
//                        .selectAs(TRecorder::getInfoid,CallResvo::getRecordurl)
//                        .selectAs(TRecorder::getSpendtime,CallResvo::getActivespan)
//                        .selectAs(ReportCallHist::getWaitspan,CallResvo::getRingspan)
//                        .selectAs(TRecorder::getInfodepart,CallResvo::getRecupload)
//                        .selectAs("fun_getnames('CTI.CALLTYPE',t.calltype)",CallResvo::getCalltype)
//                        .selectAs("fun_getnames('CTI.CALLRESULT',h.callresult)",CallResvo::getCallresult)
//                        .selectAs(String.format("fi_starSecu('%s','%s',t.telno,'%s')",$usrid,JUsrPerm.DISSTAR_PHN,phnstar),CallResvo::getAni)
//                        .selectAs(String.format("fi_starSecu('%s','%s',t.teldnis,'%s')",$usrid,JUsrPerm.DISSTAR_PHN,phnstar),CallResvo::getDnis)
//                        .selectAs("fun_getgrpname(t.agentid)",CallResvo::getGrpname)
//                        .selectAs("fun_getusername(t.agentid)",CallResvo::getUsrname)
//                        .leftJoin(ReportCallHist.class,"h",ReportCallHist::getCallmanagenumber,TRecorder::getCallid)
//                        .select(TRecorder::getCallid,TRecorder::getTaskflag,TRecorder::getUpasrdt)
//                        //.selectAs(TRecorder::getRecorderid,CallResvo::getCallid)
//                        //.select(TRecorder::getTaskflag,TRecorder::getUpasrdt)
//                        //.eq(ReportCallHist::getDevtype,"device")
//                        .apply("((h.devtype = 'device' and h.INACDGRPID is not null and t.channeldn != 'robotai') or (h.devtype = 'vdn' and t.channeldn = 'robotai'))")
//                        .apply("h.talkspan > 0")
//                        .notIn(TRecorder::getAgentid,"ivr","qm")
//                        .eq(JPubUtils.IsNotEmpty(paras.getUsrid()),TRecorder::getAgentid,paras.getUsrid())
//                        .eq(JPubUtils.IsNotEmpty(paras.getCalltype()),TRecorder::getCalltype,paras.getCalltype())
//                        .eq(JPubUtils.IsNotEmpty(paras.getCallresult()),ReportCallHist::getCallresult,paras.getCallresult())
//                        .between(JPubUtils.IsNotEmpty(paras.getStartdt()), TRecorder::getStarttime,JPubUtils.StringToDate(paras.getStartdt()),JPubUtils.StringToDate(paras.getEnddt()))
//                        .ge(JPubUtils.IsNotEmpty(paras.getTalkspan1()),TRecorder::getSpendtime,paras.getTalkspan1())
//                        .le(JPubUtils.IsNotEmpty(paras.getTalkspan2()),TRecorder::getSpendtime,paras.getTalkspan2())
//                        .apply(JPubUtils.IsNotEmpty(paras.getPhone()),"(t.telno={0} or t.teldnis={0})",paras.getPhone())
//                        .apply(JPubUtils.IsNotEmpty(paras.getGrpid()),"fc_hasUsrInGroup(t.agentid,{0})>0",paras.getGrpid())
//                        .orderByAsc(TRecorder::getStarttime)
//        );
    }

    //呼叫列表导出
    @Override
    public CmdResVo expRecordList(JSysUser user, CallReqVo paras, HttpServletResponse response)
    {
        String $usrid = user.getUsrid();
        int pagesize = paras.getPageSize();
        if (pagesize > JPubUtils.exportMaxCount) {
            paras.setPageSize(JPubUtils.exportMaxCount);
        }
        log.info("expSmsList:pagesize={}",pagesize);

        IPage<CallResVo> pages=recordList(user,paras);
        ArrayList arr=new ArrayList();

        String exptempid=JPubUtils.getExpTempID(paras.getExpfilename(),"呼叫列表数据");
        String filename=JPubUtils.getExpFileName(
                paras.getExpfilename(),exptempid
        );
        pages.convert(u->{
            HashMap map=JPubUtils.toExportMap(u);
            if(map!=null) arr.add(map);
            return u;
        });
        CmdResVo resVo=exportService.ToExcel(
                response,
                arr,
                paras.getExpidlist(),
                paras.getExpnamelist(),
                filename,
                $usrid
        );

        int okcount=resVo.getCount();
        if(okcount>0){
            FiImpAddVo addVo=new FiImpAddVo();
            addVo.setBatchid(resVo.getKeyId());
            addVo.setFilename(filename);
            addVo.setTempid(exptempid);
            addVo.setOkcount(okcount);
            String token = SpringContextUtil.getBearerToken();
            iCoreFeign.addImportHist(addVo,token);
        }
        arr.clear();

        return resVo;
    }
    /**
     * 进线组坐席监控统计
     *
     * @return 进线组坐席监控统计
     */
    @Override
    public InGroupStatisticsVO inGroupStatistics(String workStartTime,
                                                 String workEndTime) {
        InGroupStatisticsVO vo = baseMapper.inGroupStatistics(workStartTime, workEndTime);
        //  正在通话数
//        int callNum = 0;
        //  空闲客服数
        int idleAgentNum = 0;
        //  正在排队人数
        int queueNum = 0;
        //  排队放弃人数
        int queueGiveupNum = 0;
        //  离线客服数
        int offlineAgentNum = 0;
        // 获取所有进线组
        String[] groupIds = seaterMapper.getGroupByType(1);

        // 当前组的坐席
        List<CcSeater> ccSeaters = seaterMapper.getSeaterListByGroupType(1);
        for (CcSeater ccSeater : ccSeaters) {
            WebchatClientVoiceVO client = getClientVoice(ccSeater.getAccount());
            if (client != null) {
                if ("ready".equals(client.getEventkey())) {
                    idleAgentNum += 1;
                }
            }
            WebchatLineVoiceVO line = getLineVoice(ccSeater.getAccount());
            if (line != null) {
//                if ("connect".equals(line.getStatus())) {
//                    callNum += 1;
//                }
                if (!"unregister".equals(line.getStatus())) {
                    offlineAgentNum += 1;
                }
            } else {
                offlineAgentNum += 1;
            }
        }
        for (String groupId : groupIds) {
            WebchatGroupVoiceVO group = getGroupVoice(groupId);
            if (group != null) {
                queueNum += group.getQueue();
                queueGiveupNum += group.getTotalabandon();
            }
        }
        vo.setCallNum(getInCount());
        vo.setIdleAgentNum(idleAgentNum);
        vo.setOfflineAgentNum(offlineAgentNum);
        vo.setQueueNum(queueNum);
        vo.setQueueGiveupNum(queueGiveupNum);
//        // 获取redis中全部坐席
//        List<WebchatClientVoiceVO> clientVoiceVos = getAllClientVoice();
//        // 获取redis中全部线路
//        List<WebchatLineVoiceVO> lineVoiceVos = getAllLineVoice();
//        String[] seaterAccounts = ccSeaters.stream().map(CcSeater::getAccount).toArray(String[]::new);
//        for (WebchatClientVoiceVO clientVoiceVO : clientVoiceVos) {
//            if (containsObject(seaterAccounts, clientVoiceVO.getOpeid())) {
//                switch (clientVoiceVO.getEventkey()) {
//                    case "ready":
//                        idleAgentNum += 1;
//                        break;
//                }
//            }
//        }

        return vo;
    }
    /**
     * 获取当前进线通话数
     *
     * @return 当前进线通话数
     */
    private Integer getInCount() {
        int count = 0;
        List<WebchatLineVoiceVO> list = getAllLineVoice();
        for (WebchatLineVoiceVO webchatLineVoiceVO : list) {
            if ("connect".equals(webchatLineVoiceVO.getStatus()) && "IN".equals(webchatLineVoiceVO.getDirection())) {
                count += 1;
            }
        }
        return count;
    }
    @Override
    public VisitGroupStatisticsVO visitGroupStatistics() {
        VisitGroupStatisticsVO vo = baseMapper.visitGroupStatistics();
        //  正在通话数
        int callNum = 0;
        List<CcSeater> ccSeaters = seaterMapper.getSeaterListByGroupType(2);
        for (CcSeater ccSeater : ccSeaters) {
            WebchatLineVoiceVO line = getLineVoice(ccSeater.getAccount());
            if (line != null) {
                if ("connect".equals(line.getStatus())) {
                    callNum += 1;
                }
            }
        }
        vo.setCallNum(callNum);
        return vo;
    }
    /**
     * 进线组坐席监控明细
     *
     * @param dto 参数
     * @return 进线组坐席监控明细
     */
    @Override
    public List<InGroupDetailVO> inGroupDetail(InGroupDetailDTO dto) {
        List<InGroupDetailVO> vo = seaterMapper.inGroupDetail(dto);
        List<InGroupDetailVO> resultVo = new ArrayList<>();
        for (InGroupDetailVO detailVO : vo) {
            WebchatClientVoiceVO client = getClientVoice(detailVO.getAccount());
            WebchatLineVoiceVO line = getLineVoice(detailVO.getAccount());
            if (client != null) {
                String acdStatus = client.getEventkey(); // ACD状态
                String displayStatus = statusConversionService.convertAcdStatus(acdStatus); // 使用服务转换
                String disReason = client.getReason(); // 原因
                String reasonDisplay = statusConversionService.convertReason(disReason);
                if (!StringUtils.isEmpty(reasonDisplay)) {
                    displayStatus = reasonDisplay;
                }
                String ts = StringUtils.substring(client.getTs(), 0, 18);
                Date tsDate = DateUtils.dateTime("yyyy-MM-dd'T'HH:mm:ss", ts);
                detailVO.setStatus(displayStatus)
                        .setStartDate(DateUtils.parseDateToStr("HH:mm:ss", tsDate))
                        .setStatusTime(DateUtils.timeDistanceSec(new Date(), tsDate));
                // 使用服务检查状态并转换线路状态
                if (statusConversionService.isCheckLineState(acdStatus)) {
                    if (line != null) {
                        String lineStatus = line.getStatus();
                        String convertedLineStatus = statusConversionService.convertLineStatus(lineStatus);
                        if (!StringUtils.isEmpty(convertedLineStatus)) {
                            displayStatus = convertedLineStatus;
                        }
                    }
                    detailVO.setStatus(displayStatus);
                }
                resultVo.add(detailVO);
            }
        }
        return resultVo;
    }
    /**
     * 获取redis中的线路
     *
     * @param account 坐席账号
     */
    private WebchatLineVoiceVO getLineVoice(String account) {
        JSONObject jsonObject = redisService.getCacheObject("webchat.line.Voice." + account);
        if (jsonObject != null) {
            // 将 JSONObject 转换为 WebchatLineVoiceVO 对象
            return JSON.parseObject(jsonObject.toJSONString(), WebchatLineVoiceVO.class);
        }
        return null;
    }
    /**
     * 获取redis中全部线路
     */
    List<WebchatLineVoiceVO> getAllLineVoice() {
        List<WebchatLineVoiceVO> clientVoiceVos = new ArrayList<>();
        List<JSONObject> lists = redisService.getCacheListStartKey("webchat.line.Voice");
        for (JSONObject webchatLineVoiceObj : lists) {
            if (webchatLineVoiceObj != null) {
                // 将 JSONObject 转换为 WebchatLineVoiceVO 对象
                WebchatLineVoiceVO WebchatLineVoiceVO = JSON.parseObject(webchatLineVoiceObj.toJSONString(), WebchatLineVoiceVO.class);
                // 这里可以将 WebchatLineVoiceVO 添加到 WebchatLineVoiceVOS 列表中
                clientVoiceVos.add(WebchatLineVoiceVO);
            } else {
                // 处理非 JSONObject 类型的返回值
                throw new IllegalArgumentException("Expected a JSONObject but got " + webchatLineVoiceObj.getClass().getName());
            }
        }
        return clientVoiceVos;
    }
    /**
     * 获取redis中的组
     *
     * @param grpId 组id
     */
    private WebchatGroupVoiceVO getGroupVoice(String grpId) {
        JSONObject jsonObject = redisService.getCacheObject("webchat.group." + grpId);
        if (jsonObject != null) {
            // 将 JSONObject 转换为 WebchatGroupVoiceVO 对象
            return JSON.parseObject(jsonObject.toJSONString(), WebchatGroupVoiceVO.class);
        }
        return null;
    }
    /**
     * 获取redis中的电话坐席
     *
     * @param account 坐席账号
     */
    private WebchatClientVoiceVO getClientVoice(String account) {
        JSONObject jsonObject = redisService.getCacheObject("webchat.client.Voice." + account);
        if (jsonObject != null) {
            // 将 JSONObject 转换为 WebchatClientVoiceVO 对象
            return JSON.parseObject(jsonObject.toJSONString(), WebchatClientVoiceVO.class);
        }
        return null;
    }
    // 静态线路状态映射表,暂时应急，后续添加字典。
    private static final Map<String, String> LINE_STATUS_MAP = new HashMap<>();
    static {
        LINE_STATUS_MAP.put("connect", "通话中");
        LINE_STATUS_MAP.put("hold", "保留中");
        LINE_STATUS_MAP.put("consult", "咨询中");
        LINE_STATUS_MAP.put("transfer", "转接中");
        LINE_STATUS_MAP.put("conference", "会议中");
        LINE_STATUS_MAP.put("ring", "振铃中");
        LINE_STATUS_MAP.put("alerting", "振铃中");
        LINE_STATUS_MAP.put("dial", "拨号中");
        LINE_STATUS_MAP.put("compconf", "会议完成");
        LINE_STATUS_MAP.put("comptrans", "转接完成");
    }
    // 静态检查线路状态集合，暂时应急,后续添加字典。
    private static final Set<String> CHECK_LINE_STATES = new HashSet<>(Arrays.asList("ready", "notready"));
    // ACD状态转换方法，暂时应急,后续添加字典。
    private String convertAcdStatus(String status) {
        if(StringUtils.isEmpty(status))
            return "";
        switch (status) {
            case "login": return "签入";
            case "logout": return "签出";
            case "ready": return "就绪";
            case "notready": return "离席";
            case "pending": return "离席中";
            case "work": return "工作中";
            default: return "";
        }
    }
    // Reason转换方法，暂时应急,后续使用字典。
    private String convertReason(String reason) {
        if(StringUtils.isEmpty(reason))
            return "";
        switch (reason) {
            case "128": return "外呼";
            default: return "";
        }
    }

    @Override
    public List<DialogueResVo> quyAgentDialogue(String callid, String agentid)
    {
        return baseMapper.quyAgentDialogue(callid,agentid);
    }
    @Override
    public List<DialogueResVo> quyIvrDialogue(String callid)
    {
        return baseMapper.quyIvrDialogue(callid);
    }
}




